﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
using QFrameworkOne;
using QFrameworkOne.Module;


namespace QFrameworkOne.Diagnostics {
    /// <summary>
    /// 日志项目类型枚举
    /// </summary>
    public enum QDebugLogType {
        /// <summary>
        /// 冗长信息，优先级=1
        /// </summary>
        Verbose = 0,

        /// <summary>
        /// QDebug输出信息
        /// </summary>
        QDebug = 1,

        /// <summary>
        /// 调试信息，优先级=2
        /// </summary>
        Debug = 2,

        /// <summary>
        /// 重点信息，优先级=3
        /// </summary>
        Info = 3
    }

    /// <summary>
    /// QDebug控制台颜色
    /// </summary>
    public static class QDebugConsoleColor {
        /// <summary>
        /// Default,Gray
        /// </summary>
        public static ConsoleColor Default = ConsoleColor.Gray;

        /// <summary>
        /// QDebug,Blue
        /// </summary>
        public static ConsoleColor QDebug = ConsoleColor.Blue;

        /// <summary>
        /// Verbose,DarkYellow
        /// </summary>
        public static ConsoleColor Verbose = ConsoleColor.DarkYellow;

        /// <summary>
        /// Debug,Yellow
        /// </summary>
        public static ConsoleColor Debug = ConsoleColor.Yellow;

        /// <summary>
        /// Info,Cyan
        /// </summary>
        public static ConsoleColor Info = ConsoleColor.Cyan;

        /// <summary>
        /// Warning,Green
        /// </summary>
        public static ConsoleColor Warning = ConsoleColor.Green;

        /// <summary>
        /// Error,DarkRed
        /// </summary>
        public static ConsoleColor Error = ConsoleColor.DarkRed;

        /// <summary>
        /// Fatal,Magenta
        /// </summary>
        public static ConsoleColor Fatal = ConsoleColor.Magenta;

        /// <summary>
        /// Silent,Red
        /// </summary>
        public static ConsoleColor Silent = ConsoleColor.Red;
    }

    /// <summary>
    /// 错误信息项目类型枚举
    /// </summary>
    public enum QDebugErrorType {
        /// <summary>
        /// QDebug输出信息
        /// </summary>
        QDebug = 0,

        /// <summary>
        /// 警告，优先级=1
        /// </summary>
        Warning = 1,

        /// <summary>
        /// 错误，优先级=2
        /// </summary>
        Error = 2,

        /// <summary>
        /// 失败，优先级=3
        /// </summary>
        Fatal = 3,

        /// <summary>
        /// 最高优先级的错误，优先级=4
        /// </summary>
        Silent = 4
    }

    /// <summary>
    /// QDebug 微型调试器
    /// 提供基本的日志记录功能和错误记录
    /// </summary>
    public class QDebug : QComponentBase {
        /// <summary>
        /// 代码版本
        /// </summary>
        private QComponentVersion v_CodeVer = new QComponentVersion() {
            Major = 0,
            Minor = 2,
            Update = 7,
            Label = QComponentVersionLabel.Alpha
        };

        /// <summary>
        /// Log 输出(Console/File)级别，默认 QDebug
        /// </summary>
        public static QDebugLogType LogOutputLevel = QDebugLogType.Debug;

        /// <summary>
        /// Error 输出(Console/File)级别，默认 Warning
        /// </summary>
        public static QDebugErrorType ErrorOutputLevel = QDebugErrorType.Warning;

        /// <summary>
        /// QDebug默认保存日志文件的目录名
        /// </summary>
        const string QDEBUG_LOGFILEDIR = "QDiagnostics";

        /// <summary>
        /// 简单错误记录文件名
        /// </summary>
        const string QDEBUG_SIMPLE_ERRORFILENAME = "SimpleError.qd";

        /// <summary>
        /// 简单日志文件名
        /// </summary>
        const string QDEBUG_SIMPLE_LOGFILENAME = "SimpleLog.qd";

        /// <summary>
        /// QDebug应急错误日志文件
        /// </summary>
        const string QDEBUG_CRASH_ERRORFILE = "QDB_Crash_Error.qd";

        /// <summary>
        /// 是否输出到控制台，默认关闭
        /// </summary>
        public bool ConsoleOutput = false;

        /// <summary>
        /// 是否以Debug形式输出，默认打开
        /// </summary>
        public bool DebugOutput = true;

        /// <summary>
        /// 是否输出到文件，默认不输出
        /// </summary>
        public bool FileOutput = false;

        /// <summary>
        /// 简单日志记录文件路径
        /// </summary>
        public string SimpleLogFile { get; set; }

        /// <summary>
        /// 简单错误记录文件路径
        /// </summary>
        public string SimpleErrorFile { get; set; }

        /// <summary>
        /// 保存日志文件的文件夹
        /// </summary>
        public string LogFileDirectory { get; set; }

        /// <summary>
        /// 调试代码位置
        /// </summary>
        public string DebugCodeLocation = "";

        /// <summary>
        /// 调试代码位置
        /// </summary>
        public new string CodeLocation = "";

        /// <summary>
        /// 代码所在的方法
        /// </summary>
        public string CodeFunction = "";

        /// <summary>
        /// Default LogType
        /// </summary>
        public QDebugLogType LogType = QDebugLogType.Debug;

        /// <summary>
        /// Default ErrorType
        /// </summary>
        public QDebugErrorType ErrorType = QDebugErrorType.Error;

        /// <summary>
        /// 应急处理程序：用于在QDebug自身出现错误的处理
        /// </summary>
        private void CrashProc(string paramOperation, string paramError) {
            LogFileDirectory = Environment.CurrentDirectory;
            SimpleErrorFile = string.Format(@"{0}\{1}", LogFileDirectory, QDEBUG_CRASH_ERRORFILE);

            try {
                if (!Directory.Exists(LogFileDirectory))
                    Directory.CreateDirectory(LogFileDirectory);

                if (!File.Exists(SimpleErrorFile))
                    File.Create(SimpleErrorFile).Close();

                QData qd = new QData(SimpleErrorFile);
                string section = DateTime.Now.ToFileTimeUtc().ToString();
                QDataSection qds = new QDataSection(section);
                qds.Keys.Add("Operation", paramOperation);
                qds.Keys.Add("Error", paramError);
                qd.InsertSection(qds);
            }
            catch (Exception ex) {
                if (ConsoleOutput) {
                    Console.ForegroundColor = QDebugConsoleColor.Silent;
                    Console.WriteLine("完了~ 遇到连QDebug都无法处理的错误了，错误源：{0}，错误信息：{1}", ex.Source, ex.Message);
                    Console.ForegroundColor = QDebugConsoleColor.Default;
                }
            }
        }

        /// <summary>
        /// 初始化环境
        /// </summary>
        private void InitEnvironment() {
            //判断目录是否存在
            if (!Directory.Exists(LogFileDirectory)) {
                try {
                    DirectoryInfo dirInfo = new DirectoryInfo(LogFileDirectory);
                    dirInfo.Create();
                    LogFileDirectory = dirInfo.FullName;
                }
                catch (Exception ex) {
                    CrashProc("Create LogFileDirectory", ex.Message);
                }
            }

            //判断日志文件是否存在
            if (!File.Exists(SimpleLogFile)) {
                try {
                    File.Create(SimpleLogFile).Close();
                    Log("LogFile Created.", QDebugLogType.QDebug);
                }
                catch (Exception ex) {
                    CrashProc("Create SimpleLogFile", ex.Message);
                }
            }

            try {
                Log(string.Format("QDebug Start. Version: {0}", this.CodeVersion.ToString()), QDebugLogType.QDebug,
                    "InitEnvironment");
                //LogWrite(QDebugLogType.QDebug, "Thread ID=" + Environment.CurrentManagedThreadId.ToString(), "InitEnvironment");
            }
            catch (Exception ex) {
                CrashProc("Write QDB Start Log", ex.Message);
            }

            //判断错误记录文件是否存在
            if (!File.Exists(SimpleErrorFile)) {
                try {
                    File.Create(SimpleErrorFile).Close();
                    Error("ErrorLogFile Created.", QDebugErrorType.QDebug);
                }
                catch (Exception ex) {
                    CrashProc("Create SimpleErrorFile", ex.Message);
                }
            }
        }

        /// <summary>
        /// 默认构造函数，以当前程序运行目录下的"QDB"文件夹保存日志文件
        /// </summary>
        public QDebug() {
            CodeVersion = v_CodeVer;
            LogFileDirectory = string.Format(@"{0}\{1}", Environment.CurrentDirectory, QDEBUG_LOGFILEDIR);
            SimpleErrorFile = string.Format(@"{0}\{1}", LogFileDirectory, QDEBUG_SIMPLE_ERRORFILENAME);
            SimpleLogFile = string.Format(@"{0}\{1}", LogFileDirectory, QDEBUG_SIMPLE_LOGFILENAME);
            InitEnvironment();
        }

        /// <summary>
        /// 自定义的记录文件保存目录，如果不存在将自动创建
        /// </summary>
        /// <param name="paramLogFileDirectory">文件保存目录</param>
        public QDebug(string paramLogFileDirectory) {
            CodeVersion = v_CodeVer;
            LogFileDirectory = paramLogFileDirectory;
            SimpleErrorFile = string.Format(@"{0}\{1}", LogFileDirectory, QDEBUG_SIMPLE_ERRORFILENAME);
            SimpleLogFile = string.Format(@"{0}\{1}", LogFileDirectory, QDEBUG_SIMPLE_LOGFILENAME);
            InitEnvironment();
        }

        /// <summary>
        /// 自定义日志文件和错误文件，如果不存在将自动创建
        /// </summary>
        /// <param name="paramLogFile">日志文件</param>
        /// <param name="paramErrorFile">错误文件</param>
        public QDebug(string paramLogFile, string paramErrorFile) {
            LogFileDirectory = Path.GetDirectoryName(paramLogFile);
            SimpleLogFile = paramLogFile;
            SimpleErrorFile = paramErrorFile;
            InitEnvironment();
        }

        /// <summary>
        /// 输出一行，不会保存日志
        /// </summary>
        /// <param name="pContent">内容</param>
        public void WriteLine(string pContent) {
            if (DebugOutput)
                Debug.WriteLine(pContent);

            if (ConsoleOutput) {
                Console.ForegroundColor = QDebugConsoleColor.Debug;
                Console.WriteLine(pContent);
                Console.ForegroundColor = QDebugConsoleColor.Default;
            }
        }

        /// <summary>
        /// 输出一行，不会保存日志
        /// </summary>
        /// <param name="pContent">内容</param>
        /// <param name="pType">类型</param>
        public void WriteLine(string pContent, QDebugLogType pType) {
            if (DebugOutput)
                Debug.WriteLine(pContent);

            if (ConsoleOutput) {
                switch (pType) {
                    case QDebugLogType.Debug:
                        Console.ForegroundColor = QDebugConsoleColor.Debug;
                        break;
                    case QDebugLogType.Info:
                        Console.ForegroundColor = QDebugConsoleColor.Info;
                        break;
                    case QDebugLogType.QDebug:
                        Console.ForegroundColor = QDebugConsoleColor.QDebug;
                        break;
                    case QDebugLogType.Verbose:
                        Console.ForegroundColor = QDebugConsoleColor.Verbose;
                        break;
                }

                Console.WriteLine(pContent);
                Console.ForegroundColor = QDebugConsoleColor.Default;
            }
        }

        /// <summary>
        /// 输出一行，不会保存日志
        /// </summary>
        /// <param name="pContent">内容</param>
        /// <param name="pType">类型</param>
        /// <param name="pFunction">方法名称</param>
        public void WriteLine(string pContent, QDebugLogType pType, string pFunction) {
            pContent = string.Format("{0}->{1}", pFunction, pContent);

            if (DebugOutput)
                Debug.WriteLine(pContent);

            if (ConsoleOutput) {
                switch (pType) {
                    case QDebugLogType.Debug:
                        Console.ForegroundColor = QDebugConsoleColor.Debug;
                        break;
                    case QDebugLogType.Info:
                        Console.ForegroundColor = QDebugConsoleColor.Info;
                        break;
                    case QDebugLogType.QDebug:
                        Console.ForegroundColor = QDebugConsoleColor.QDebug;
                        break;
                    case QDebugLogType.Verbose:
                        Console.ForegroundColor = QDebugConsoleColor.Verbose;
                        break;
                }

                Console.WriteLine(pContent);
                Console.ForegroundColor = QDebugConsoleColor.Default;
            }
        }

        /// <summary>
        /// 记录日志，同时输出
        /// </summary>
        /// <param name="format">待格式化字符串</param>
        /// <param name="args">参数</param>
        public void Log(string format, params object[] args) {
            Log(string.Format(format, args), LogType, CodeFunction);
        }

        /// <summary>
        /// 记录日志，同时输出
        /// </summary>
        /// <param name="paramType">日志类型</param>
        /// <param name="paramContent">日志内容</param>
        /// <param name="paramFunction">产生日志的方法名称</param>
        public void Log(string paramContent, QDebugLogType paramType = QDebugLogType.Debug,
            string paramFunction = "UnknownFunc") {
            //文件输出
            if (FileOutput && paramType >= LogOutputLevel) {
                QData qd = new QData(SimpleLogFile);
                string section = DateTime.Now.ToFileTimeUtc().ToString();
                QDataSection qds = new QDataSection(section);
                qds.Keys.Add("Time", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
                qds.Keys.Add("Type", paramType.ToString());
                qds.Keys.Add("DebugCodeLocation", DebugCodeLocation);
                qds.Keys.Add("CodeLocation", CodeLocation);
                qds.Keys.Add("Function", paramFunction);
                qds.Keys.Add("Content", paramContent);
                qd.InsertSection(qds);
            }

            string logMsg = "";

            DebugCodeLocation = CodeLocation;

            if (paramType == QDebugLogType.QDebug)
                logMsg = string.Format("[QDebug] - [Log] - [{0}] {1}.({2})->{3}", "QFramework", DebugCodeLocation,
                    paramFunction, paramContent);
            else
                logMsg = string.Format("[Qdb] - [Log] - [{0}] {1}.({2})->{3}", paramType.ToString(), DebugCodeLocation,
                    paramFunction, paramContent);


            if (DebugOutput)
                Debug.WriteLine(logMsg);

            if (ConsoleOutput && paramType >= LogOutputLevel) {
                switch (paramType) {
                    case QDebugLogType.Debug:
                        Console.ForegroundColor = QDebugConsoleColor.Debug;
                        break;
                    case QDebugLogType.Info:
                        Console.ForegroundColor = QDebugConsoleColor.Info;
                        break;
                    case QDebugLogType.QDebug:
                        Console.ForegroundColor = QDebugConsoleColor.QDebug;
                        break;
                    case QDebugLogType.Verbose:
                        Console.ForegroundColor = QDebugConsoleColor.Verbose;
                        break;
                }

                Console.WriteLine(logMsg);
                Console.ForegroundColor = QDebugConsoleColor.Default;
            }
        }

        /// <summary>
        /// 记录错误信息，同时输出
        /// </summary>
        /// <param name="format">待格式化字符串</param>
        /// <param name="args">参数</param>
        public void Error(string format, params object[] args) {
            Error(string.Format(format, args), ErrorType, CodeFunction);
        }

        /// <summary>
        /// 记录错误信息，同时输出
        /// </summary>
        /// <param name="paramType">错误类型</param>
        /// <param name="paramContent">日志内容</param>
        /// <param name="paramFunction">产生错误的方法名称</param>
        public void Error(string paramContent, QDebugErrorType paramType = QDebugErrorType.Error,
            string paramFunction = "UnknownFunc") {
            //文件输出
            if (FileOutput && paramType >= ErrorOutputLevel) {
                QData qd = new QData(SimpleErrorFile);
                string section = DateTime.Now.ToFileTimeUtc().ToString();
                QDataSection qds = new QDataSection(section);
                qds.Keys.Add("Time", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
                qds.Keys.Add("Type", paramType.ToString());
                qds.Keys.Add("DebugCodeLocation", DebugCodeLocation);
                qds.Keys.Add("CodeLocation", CodeLocation);
                qds.Keys.Add("Function", paramFunction);
                qds.Keys.Add("Content", paramContent);
                qd.InsertSection(qds);
            }

            string errorMsg = "";

            DebugCodeLocation = CodeLocation;

            if (paramType == QDebugErrorType.QDebug)
                errorMsg = string.Format("[Qdb] - [Error] - [{0}] {1}.({2})->{3}", "QFramework", DebugCodeLocation,
                    paramFunction, paramContent);
            else
                errorMsg = string.Format("[Qdb] - [Error] - [{0}] {1}.({2})->{3}", paramType.ToString(),
                    DebugCodeLocation, paramFunction, paramContent);


            if (DebugOutput)
                Debug.WriteLine(errorMsg);

            if (ConsoleOutput && paramType >= ErrorOutputLevel) {
                switch (paramType) {
                    case QDebugErrorType.Error:
                        Console.ForegroundColor = QDebugConsoleColor.Error;
                        break;
                    case QDebugErrorType.Fatal:
                        Console.ForegroundColor = QDebugConsoleColor.Fatal;
                        break;
                    case QDebugErrorType.QDebug:
                        Console.ForegroundColor = QDebugConsoleColor.QDebug;
                        break;
                    case QDebugErrorType.Silent:
                        Console.ForegroundColor = QDebugConsoleColor.Silent;
                        break;
                    case QDebugErrorType.Warning:
                        Console.ForegroundColor = QDebugConsoleColor.Warning;
                        break;
                }

                Console.WriteLine(errorMsg);
                Console.ForegroundColor = QDebugConsoleColor.Default;
            }
        }
    }

    /// <summary>
    /// 管理日志文件的类
    /// </summary>
    public class QDebugLog {
        /// <summary>
        /// 日志文件
        /// </summary>
        public string LogFile { get; set; }

        /// <summary>
        /// 日志时间
        /// </summary>
        public DateTime LogTime { get; set; }

        /// <summary>
        /// 日志类型
        /// </summary>
        public QDebugLogType LogType { get; set; }

        /// <summary>
        /// 日志内容
        /// </summary>
        public string LogContent { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="paramLogFile">日志文件</param>
        public QDebugLog(string paramLogFile) {
            LogFile = paramLogFile;
        }
    }

    /// <summary>
    /// 管理错误文件的类
    /// </summary>
    public class QDebugError {
        /// <summary>
        /// 错误文件
        /// </summary>
        public string ErrorFile { get; set; }

        /// <summary>
        /// 日志时间
        /// </summary>
        public DateTime LogTime { get; set; }

        /// <summary>
        /// 错误日志类型
        /// </summary>
        public QDebugLogType LogType { get; set; }

        /// <summary>
        /// 日志内容
        /// </summary>
        public string LogContent { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="paramErrorFile">错误文件</param>
        public QDebugError(string paramErrorFile) {
            ErrorFile = paramErrorFile;
        }
    }
}